#ifndef __MOVING_OBJECT_H
#define __MOVING_OBJECT_H

#include <vector>
#include <map>

#define WAITING (0)
#define ACCELERATING (1)
#define MOVING (2)
#define DECELERATING (3)

#define MAX_ROTATE_DIST (5)

typedef struct path_node {
    Ogre::Vector3 position;
    Ogre::Real speed;
    Ogre::Real delay;
    bool rotate;
    bool wait_for_ball;
} PathNode;

class MovingObject : public Ogre::FrameListener, public OgreNewt::ContactCallback {
private:
    OgreNewt::Body* body;
    Ogre::SceneNode *ogre_node;
    
    OgreNewt::BasicJoints::UpVector *up_joint;
    OgreNewt::BasicJoints::Slider *movement_joint;
    OgreNewt::BasicJoints::Slider *next_movement_joint;
    
    Ogre::Vector3 current_direction;
        
    std::vector<PathNode> path_nodes;
    unsigned current_target;
    
    int state;
    Ogre::Real target_distance, target_speed;
    Ogre::Real current_speed, current_delay;
    Ogre::Real wait_duration;
    Ogre::Real deceleration_distance;
    Ogre::Real original_mass;
    Ogre::Vector3 original_inertia;
    Ogre::Vector3 original_position;
    Ogre::Quaternion original_orientation;
    bool initial_wait, waiting_for_ball;
        
    Ogre::Real default_speed;
    Ogre::Real default_delay;
            
    static PathNode createPathNode(Ogre::String name, 
                                      std::map<Ogre::String, Ogre::String> *node_id_map, 
                                      Ogre::Vector3 position);
    
    OgreNewt::BasicJoints::Slider *createMovementJoint();
    
    // default constructor is private
    MovingObject();
public:
    MovingObject( OgreNewt::Body* b, 
                  std::map<Ogre::String, Ogre::String> *childNodeIDs);
    ~MovingObject();
    
    void setMaterialID(OgreNewt::MaterialID *mat_id);
    Ogre::Real getCurrentSpeed();
    void setCurrentSpeed(Ogre::Real s);
    Ogre::Real getTargetSpeed();
    Ogre::Real getTargetDistance();
    Ogre::Real getRotateDistance();
    void setDecelerationDistance(Ogre::Real d);
    Ogre::Real getDecelerationDistance();
    bool isWaitingForBall();
    void setWaitingForBall(bool w);
    
    int getState();
    void setState(int s);
    void atTarget();
    void freeze();
    void unfreeze();
    
    void init();
    void reset();
    	
    void ballCollision();
	//int userBegin();
    //int userProcess();
    
    static void sliderCallback(OgreNewt::BasicJoints::Slider *slider);
	
    bool frameStarted(Ogre::Real time);
    
    MovingObject *clone(Ogre::SceneManager *scene_mgr, Ogre::String suffix, int new_player_id);
};


#endif
